package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.zzyl.base.ResponseResult;
import com.zzyl.dto.*;
import com.zzyl.entity.AccraditationRecord;
import com.zzyl.entity.CheckIn;
import com.zzyl.entity.CheckInConfig;
import com.zzyl.entity.Elder;
import com.zzyl.enums.*;
import com.zzyl.mapper.*;
import com.zzyl.service.CheckInService;
import com.zzyl.service.WorkFlowService;
import com.zzyl.vo.LoginUserVo;
import com.zzyl.vo.TasVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class CheckInServiceImpl implements CheckInService {

    @Resource
    CheckInMapper checkInMapper;

    @Resource
    ElderMapper elderMapper;

    @Resource
    SysUserMapper sysUserMapper;

    @Resource
    AccraditationRecordMapper recordMapper;

    @Resource
    CheckInConfigMapper checkInConfigMapper;

    @Resource
    WorkFlowService workFlowService;

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    private static final String CHECK_IN_CODE_PREFIX = "RZ";

    private static final String ASSIGNEE_PREFIX = "assignee";


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult createChickIn(CheckInDto dto, LoginUserVo userVo) {

        //校验重复申请数据
        ElderDto elderDto = dto.getElderDto();
        Elder elder = elderMapper.selectByIdCard(elderDto.getIdCardNo());
        if (Objects.nonNull(elder)) {
            return ResponseResult.error("该老人已申请");
        }
        //保存老人信息
        Elder insertElder = BeanUtil.toBean(dto.getElderDto(), Elder.class);
        insertElder.setImage(dto.getUrl1());
        insertElder.setStatus(CheckInStatusEnum.CHECKING_IN.getCode());
        int insert = elderMapper.insert(insertElder);
        log.info("插入老人表{}", insert);
        CheckIn checkIn = new CheckIn();
        checkIn.setTitle(elderDto.getName() + "的入住申请");
        checkIn.setElderId(insertElder.getId());
        checkIn.setCounselor(userVo.getNickName());
        checkIn.setApplicat(userVo.getNickName());
        checkIn.setApplicatId(userVo.getId());
        checkIn.setDeptNo(userVo.getDeptNo());
        checkIn.setStatus(ApplicationStatusEnum.APPLICATION.getCode());
        checkIn.setOtherApplyInfo(JSONObject.toJSONString(dto));
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String checkInCode = CHECK_IN_CODE_PREFIX + LocalDateTime.now().format(pattern);
        checkIn.setCheckInCode(checkInCode);
        checkIn.setFlowStatus(FlowStatus.REVIEW.getCode());
        checkInMapper.insert(checkIn);
        //todo 待完善 开启工作流
        //保存操作记录
        insertOperationRecord(userVo, checkIn);
        //启动工作流程
        HashMap<String, Object> map = new HashMap<>();
        map.put("assignee0", redisTemplate.opsForHash().get("assignee", "assignee0"));
        map.put("assignee1", redisTemplate.opsForHash().get("assignee", "assignee1"));
        map.put("assignee2", redisTemplate.opsForHash().get("assignee", "assignee2"));
        map.put("assignee3", redisTemplate.opsForHash().get("assignee", "assignee3"));
        map.put("assignee4", redisTemplate.opsForHash().get("assignee", "assignee4"));
        workFlowService.startProcess("入住申请流程"
                , checkIn.getId().toString(), map);
        //自动完成
        Map<String, Object> okMap = new HashMap<>();
        okMap.put("opinion", "同意");
        workFlowService.completeTask(userVo.getId().toString(), okMap);
        return ResponseResult.success();
    }

    private void insertOperationRecord(LoginUserVo userVo, CheckIn checkIn) {
        AccraditationRecord record = new AccraditationRecord();
        record.setApproverId(userVo.getId());
        record.setApproverName(userVo.getNickName());
        record.setApproverNameRole(userVo.getPostName());
        record.setOpinion("同意");
        record.setType(OperationRecordTypeEnum.CHECK_IN.getCode());
        //查询护理组主管信息
        Integer flowStatus = checkIn.getFlowStatus();
        String hashKey = ASSIGNEE_PREFIX + flowStatus;
        //从redis中取下一个待办人的id
        Object nextId = redisTemplate.opsForHash().get(ASSIGNEE_PREFIX, hashKey);

        Long l = Long.valueOf(nextId.toString());
        LoginUserVo nextUser = sysUserMapper.selectByPrimaryKey(l);
        record.setNextApproverId(nextUser.getId());
        record.setNextApprover(nextUser.getRealName());
        record.setNextApproverRole(nextUser.getPostName());
        record.setBussniessId(checkIn.getId());
        //使用枚举实现的策略模式实现步骤的动态填充
        String[] steps = FlowStatus.getSteps(flowStatus);
        record.setCurrentStep(steps[0]);
        record.setNextStep(steps[1]);
        record.setAuditStatus(OperationAuditStatusEnum.PASS.getCode());
        record.setHandleType(OperationHandleTypeEnum.HANDLED.getCode());
        record.setCreateBy(userVo.getId());
        record.setCreator(userVo.getRealName());
        record.setUpdateBy(userVo.getId());
        record.setUpdater(userVo.getRealName());
        record.setCreateTime(LocalDateTime.now());
        record.setUpdateTime(LocalDateTime.now());
        int operationInsert = recordMapper.insert(record);
        log.info("插入审批记录{}", operationInsert);
    }

    @Override
    public ResponseResult<TasVo> getTaskDetail(CheckInDetailDTO dto) {

        //根据code查询入驻申请表
        CheckIn checkIn = checkInMapper.queryByCode(dto.getCode());
        if (Objects.isNull(checkIn)) {
            return ResponseResult.error("未查询到入住申请信息");
        }
        String otherApplyInfo = checkIn.getOtherApplyInfo();
        CheckInDto checkInDto = JSONObject.parseObject(otherApplyInfo, CheckInDto.class);
        checkInDto.setApplicat(checkIn.getApplicat());
        checkInDto.setApplicatId(String.valueOf(checkIn.getApplicatId()));
        checkInDto.setCheckInCode(checkIn.getCheckInCode());
        checkInDto.setDeptNo(checkIn.getDeptNo());
        checkInDto.setElderId(checkIn.getElderId());
        checkInDto.setId(checkIn.getId());
        checkInDto.setTitle(checkIn.getTitle());
        checkInDto.setCounselor(checkIn.getCounselor());
        checkInDto.setFlowStatus(checkIn.getFlowStatus());
        checkInDto.setStatus(checkIn.getStatus());
        checkInDto.setCreateTime(checkIn.getCreateTime());
        checkInDto.setUpdateTime(checkIn.getUpdateTime());
        checkInDto.setIsShow(1);
        //查询操作记录
        List<AccraditationRecord> records = recordMapper.queryByBusinessId(checkIn.getId());
        TasVo tasVo = new TasVo();
        tasVo.setAccraditationRecords(records);
        tasVo.setIsShow(1);
        tasVo.setCheckIn(checkInDto);
        //之后从缓存中取
        tasVo.setNextApprover("副院长");
        tasVo.setType(OperationRecordTypeEnum.CHECK_IN.getCode());
        return ResponseResult.success(tasVo);
    }

    @Override
    @Transactional
    public ResponseResult review(ReviewDTO reviewDTO, LoginUserVo userVo) {
        //更新入住老人评估信息
        CheckIn checkIn = new CheckIn();
        checkIn.setId(reviewDTO.getId());
        checkIn.setFlowStatus(FlowStatus.APPROVAL.getCode());
        checkIn.setReviewInfo(JSONObject.toJSONString(reviewDTO));
        checkIn.setUpdateTime(LocalDateTime.now());
        int update = checkInMapper.update(checkIn);
        log.info("更新入住信息申请{}", update);
        if (update > 0) {
            //保存操作记录
            insertOperationRecord(userVo, checkIn);
        }
        //完成流程到副院长/院长审批
        HashMap<String, Object> map = new HashMap<>();
        map.put("opinion", "同意");
        workFlowService.completeTaskByTaskId(reviewDTO.getTaskId(), map);
        return ResponseResult.success();
    }

    @Override
    @Transactional
    public ResponseResult agree(AgreeDTO dto, LoginUserVo userVo) {
        CheckIn checkIn = new CheckIn();
        checkIn.setId(dto.getId());
        checkIn.setFlowStatus(FlowStatus.CONFIG.getCode());
        checkIn.setReason(dto.getMessage());
        checkIn.setUpdateTime(LocalDateTime.now());
        int update = checkInMapper.update(checkIn);
        log.info("更新入住信息申请{}", update);
        if (update > 0) {
            //保存操作记录
            insertOperationRecord(userVo, checkIn);
        }
        //完成流程到养老顾问
        HashMap<String, Object> map = new HashMap<>();
        map.put("opinion", "同意");
        map.put("ops", 1);
        workFlowService.completeTaskByTaskId(dto.getTaskId(), map);
        return ResponseResult.success();
    }

    @Override
    @Transactional
    public ResponseResult reject(AgreeDTO dto, LoginUserVo loginUser) {
        CheckIn checkIn = checkInMapper.queryById(dto.getId());
        int i = elderMapper.deleteByPrimaryKey(checkIn.getElderId());
        checkIn.setReason(dto.getMessage());
        int update = checkInMapper.update(checkIn);
        if (update > 0) {
            //保存操作记录
            AccraditationRecord record = new AccraditationRecord();
            record.setOpinion("拒绝");
            record.setType(OperationRecordTypeEnum.CHECK_IN.getCode());
            record.setApproverId(loginUser.getId());
            record.setApproverName(loginUser.getRealName());
            record.setBussniessId(dto.getId());
            record.setCurrentStep("院长处理-入住审批");
            record.setAuditStatus(OperationAuditStatusEnum.REFUSE.getCode());
            record.setStepNo(3L);
            record.setCreateTime(LocalDateTime.now());
            record.setHandleType(OperationHandleTypeEnum.HANDLED.getCode());
            record.setUpdateTime(LocalDateTime.now());
            int insert = recordMapper.insert(record);
        }
        //完成流程
        HashMap<String, Object> map = new HashMap<>();
        map.put("opinion", "拒绝");
        map.put("ops", 2);
        workFlowService.completeTaskByTaskId(dto.getTaskId(), map);
        return ResponseResult.success();
    }

    @Override
    @Transactional
    public ResponseResult disapprove(Long id, String message, String taskId, LoginUserVo userVo) {
        CheckIn checkIn = checkInMapper.queryById(id);
        checkIn.setReason(message);
        checkIn.setFlowStatus(CheckIn.FlowStatus.APPLY.getCode());
        checkIn.setReviewInfo(null);
        int update = checkInMapper.update(checkIn);
        if (update > 0){
            //删除老人数据
            elderMapper.deleteByPrimaryKey(checkIn.getElderId());
            //保存操作记录
            AccraditationRecord record = new AccraditationRecord();
            record.setApproverId(userVo.getId());
            record.setApproverName(userVo.getNickName());
            record.setApproverNameRole(userVo.getPostName());
            record.setOpinion(message);
            record.setType(OperationRecordTypeEnum.CHECK_IN.getCode());
            //查询护理组主管信息
            Integer flowStatus = checkIn.getFlowStatus();
            String hashKey = ASSIGNEE_PREFIX + flowStatus;
            //从redis中取下一个待办人的id
            Object nextId = redisTemplate.opsForHash().get(ASSIGNEE_PREFIX, hashKey);

            Long l = Long.valueOf(nextId.toString());
            LoginUserVo nextUser = sysUserMapper.selectByPrimaryKey(l);
            record.setNextApproverId(nextUser.getId());
            record.setNextApprover(nextUser.getRealName());
            record.setNextApproverRole(nextUser.getPostName());
            record.setBussniessId(checkIn.getId());
            //使用枚举实现的策略模式实现步骤的动态填充
            record.setCurrentStep("驳回申请-入住审批");
            record.setNextStep("养老顾问处理-入住申请");
            record.setAuditStatus(OperationAuditStatusEnum.REJECT.getCode());
            record.setHandleType(OperationHandleTypeEnum.HANDLED.getCode());
            record.setCreateBy(userVo.getId());
            record.setCreator(userVo.getRealName());
            record.setUpdateBy(userVo.getId());
            record.setUpdater(userVo.getRealName());
            record.setCreateTime(LocalDateTime.now());
            record.setUpdateTime(LocalDateTime.now());
            int operationInsert = recordMapper.insert(record);
            log.info("插入审批记录{}", operationInsert);
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("ops", 3);
        workFlowService.completeTaskByTaskId(taskId, map);
        return ResponseResult.success();
    }

    @Override
    @Transactional
    public ResponseResult checkIn(CheckInConfigDTO dto,LoginUserVo userVo) {
        CheckInConfig checkInConfig = new CheckInConfig();
        //插入入住配置表
        checkInConfig.setElderId(Long.valueOf(dto.getElderId()));
        checkInConfig.setCheckInStartTime(dto.getCheckInStartTime());
        checkInConfig.setCheckInEndTime(dto.getCheckInEndTime());
        checkInConfig.setNursingLevelId(Long.valueOf(dto.getNursingLevelId()));
        checkInConfig.setBedNo(dto.getBedNumber());
        checkInConfig.setCostStartTime(dto.getCostStartTime());
        checkInConfig.setCostEndTime(dto.getCostEndTime());
        checkInConfig.setDepositAmount(new BigDecimal(dto.getDepositAmount()));
        checkInConfig.setNursingCost(BigDecimal.valueOf(dto.getNursingCost()));
        checkInConfig.setBedCost(BigDecimal.valueOf(dto.getBedCost()));
        checkInConfig.setOtherCost(new BigDecimal(dto.getOtherCost()));
        checkInConfig.setMedicalInsurancePayment(BigDecimal.valueOf(dto.getMedicalInsurancePayment()));
        checkInConfig.setGovernmentSubsidy(BigDecimal.valueOf(dto.getGovernmentSubsidy()));
        checkInConfig.setCreateTime(LocalDateTime.now());
        checkInConfig.setUpdateTime(LocalDateTime.now());
        checkInConfig.setCreateBy(userVo.getId());
        checkInConfig.setUpdateBy(userVo.getId());
        String remark = StrUtil.format("{}:{}:{}:{}:{}",
                dto.getFloorId(),
                dto.getRoomId(),
                dto.getBedId(),
                dto.getFloorName(),
                dto.getCode());
        checkInConfig.setRemark(remark);
        checkInConfigMapper.insert(checkInConfig);
        //更新入住表
        CheckIn checkIn = new CheckIn();
        checkIn.setId(dto.getCheckInId());
        checkIn.setFlowStatus(FlowStatus.SIGN.getCode());
        checkIn.setUpdateTime(LocalDateTime.now());
        checkIn.setRemark("你懂的");
        int update = checkInMapper.update(checkIn);
        if (update > 0) {
            //保存操作记录
            insertOperationRecord(userVo, checkIn);
        }
        //更新老人表
        Elder elder = elderMapper.selectByPrimaryKey(checkInConfig.getElderId());
        elder.setBedId(Long.valueOf(dto.getBedId()));
        elder.setBedNumber(dto.getBedNumber());
        elderMapper.updateByPrimaryKeySelective(elder);
        //完成到法务
        HashMap<String, Object> map = new HashMap<>();
        map.put("ops",1);
        workFlowService.completeTaskByTaskId(dto.getTaskId(),map);
        return ResponseResult.success();
    }

}
